#include <arpa/inet.h>
#include <errno.h>
#include <netinet/in.h>
#include <stdio.h>
#include <string.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <unistd.h>

#include <thread>

const int kListenPort = 1111;

int main() {
  int listen_sock = socket(AF_INET, SOCK_STREAM, 0);
  if (listen_sock < 0) {
    printf("socket error(%d):%s\n", errno, strerror(errno));
    return 0;
  }

  printf("listen_sock:%d\n", listen_sock);
  struct sockaddr_in addr;
  addr.sin_family = AF_INET;
  addr.sin_addr.s_addr = INADDR_ANY;
  addr.sin_port = htons(kListenPort);
  if (bind(listen_sock, (struct sockaddr*)&addr, sizeof(addr)) < 0) {
    printf("bind error(%d):%s\n", errno, strerror(errno));
    return 0;
  }

  if (listen(listen_sock, 2) < 0) {
    printf("listen error(%d):%s\n", errno, strerror(errno));
    return 0;
  }

  std::this_thread::sleep_for(std::chrono::seconds(10));

  struct sockaddr_in peer_addr;
  memset(&peer_addr, 0, sizeof(peer_addr));
  socklen_t peer_socklen = sizeof(peer_addr);
  while (1) {
    printf("start accept...\n");
    int conn_sock =
        accept(listen_sock, (struct sockaddr*)&peer_addr, &peer_socklen);
    if (conn_sock < 0) {
      printf("accept error(%d):%s\n", errno, strerror(errno));
      return 0;
    } else {
      printf("accept one. conn_sock:%d, peer_addr:%s, peer_port:%d\n",
             conn_sock, inet_ntoa(peer_addr.sin_addr),
             ntohs(peer_addr.sin_port));
      char buff[32];
      strcpy(buff, "welcome, please input:\n");
      ssize_t n = write(conn_sock, buff, strlen(buff));

      memset(buff, 0, sizeof(buff));
      n = read(conn_sock, buff, sizeof(buff) - 1);
      if (n < 0) {
        printf("read error(%d):%s\n", errno, strerror(errno));
        return 0;
      }
      printf("read %ld bytes:%s", n, buff);
      if (n == 0) {
        printf("client closed, there close too.\n");
        close(conn_sock);
      } else {
        n = write(conn_sock, buff, strlen(buff));
        printf("echo %ld bytes:%s", n, buff);
      }
    }
  }

  printf("return\n");
}
